package com.mimo.admin.controller;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.mimo.admin.config.AdminServerConfig;
import com.mimo.admin.exception.MismatchPasswordException;
import com.mimo.admin.exception.UserIsNotExistException;
import com.mimo.common.exception.CommonMessageException;
import com.mimo.common.result.BaseResult;

@Controller
@EnableConfigurationProperties(value = { AdminServerConfig.class })
public class IndexController {
  private static final Logger logger = LoggerFactory.getLogger(IndexController.class);

  @Autowired
  private AdminServerConfig serverConfig;
  
  @PostMapping(value = "/login")
  @ResponseBody
  public BaseResult login(@RequestParam String userCode, @RequestParam String password) {

    String errMsg = "";
    UsernamePasswordToken token = new UsernamePasswordToken(userCode, password);

    try {

      // 在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
      // 每个Realm都能在必要时对提交的AuthenticationTokens作出反应
      // 所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法

      logger.info("对用户[{}]进行登录验证..验证开始", userCode);
      SecurityUtils.getSubject().logout();
      SecurityUtils.getSubject().login(token);
      logger.info("对用户[{}]进行登录验证..验证通过", userCode);

    } catch (UnknownAccountException uae) {
      logger.error("对用户[{}]进行登录验证..验证未通过,未知账户", userCode);
      errMsg = "验证未通过,未知账户";
    } catch (LockedAccountException lae) {
      logger.error("对用户[{}]进行登录验证..验证未通过,账户已锁定", userCode);
      errMsg = "账户已锁定";
    } catch (DisabledAccountException dae) {
      logger.error("对用户[{}]进行登录验证..验证未通过,账户已禁用", userCode);
      errMsg = "账户已禁用";
    } catch (IncorrectCredentialsException ice) {
      logger.error("对用户[{}]进行登录验证..验证未通过,错误的凭证", userCode);
      errMsg = "错误的凭证";
    } catch (AuthenticationException ae) {
      // 通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
      logger.error("对用户[{}]进行登录验证..验证未通过", userCode);
      errMsg = "账户或密码错误";
    } catch (MismatchPasswordException ae) {
      errMsg = "账户或密码错误";
    } catch (UserIsNotExistException ae) {
      errMsg = "账户不存在";
    }

    if (StringUtils.hasText(errMsg)) {
      throw new CommonMessageException(errMsg);
    }

    Session session = SecurityUtils.getSubject().getSession();
    session.setAttribute("userCode", userCode);
    session.setAttribute("devtoolsDetectEnable", serverConfig.isDevtoolsDetectEnable());

    return BaseResult.SUCCESS_RET;
  }

  @GetMapping(value = "/main")
  public String main() {
    return "main";
  }

  @GetMapping("/403")
  public String unauthorized() {
    logger.info("------login unauthorized-------");
    return "redirect:/login";
  }

  @GetMapping(value = "/")
  public String index() {
    return "redirect:/login";
  }

  @GetMapping(value = "/login")
  public ModelAndView login() {

    ModelAndView mav = new ModelAndView("login");
    mav.addObject("devtoolsDetectEnable", serverConfig.isDevtoolsDetectEnable());

    return mav;
  }

  @GetMapping(value = "/devtools")
  public String devtoolsHint(HttpServletRequest request, @RequestParam String pathname) {
  
    return "devtoolsHint";
  }

}
